home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gamers Delight 2
/
Gamers Delight 2.iso
/
Aminet
/
game
/
role
/
pinfocom_3_0.lha
/
Source
/
file.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-22
|
13KB
|
494 lines
/* file.c
*
* ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
* Copyright (C) 1987-1992 InfoTaskForce
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to the
* Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Header: RCS/file.c,v 3.0 1992/10/21 16:56:19 pds Stab $
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "infocom.h"
#ifdef NEED_ERRNO
extern int errno;
#endif
static const char *fname_lst[] = {FNAME_LST,0};
static const char *fext_lst[] = {"",FEXT_LST,0};
static FILE *game_file;
static char gname[MAXPATHLEN + 1];
char sname[MAXPATHLEN + 1];
#ifdef SCRIPT_FILE
char script_fn[MAXPATHLEN+1] = SCRIPT_FILE;
#else
char script_fn[MAXPATHLEN+1];
#endif
void
f_error A3(int, erno, const char *, err, const char *, arg1)
{
char buf[256];
char *bp;
sprintf(buf, err, arg1);
bp = buf + strlen(buf);
if (erno)
{
#ifndef NO_STRERROR
extern char *strerror P((int));
char *cp = strerror(erno);
sprintf(bp, ": %o: %s", erno, cp == NULL ? "<unknown>" : cp);
#else
sprintf(bp, ": %o", erno);
#endif
}
if (gflags.game_state == NOT_INIT)
{
fputs(buf, stderr);
putc('\n', stderr);
putc('\n', stderr);
}
else
{
scr_putmesg(buf, 1);
}
}
static void
assign A2(header_t*, head, const header_t*, buffer)
{
const byte *ptr;
int i;
/*
* Process the raw header data in "buffer" and put
* it into the appropriate fields in "head". This
* processing is required because of the way different
* machines internally represent 'words'.
*/
ptr = (const byte *)buffer;
head->z_version = Z_TO_BYTE_I(ptr);
head->flags_1 = Z_TO_BYTE_I(ptr);
head->release = Z_TO_WORD_I(ptr);
head->resident_bytes = Z_TO_WORD_I(ptr);
head->game_o = Z_TO_WORD_I(ptr);
head->vocab_o = Z_TO_WORD_I(ptr);
head->object_o = Z_TO_WORD_I(ptr);
head->variable_o = Z_TO_WORD_I(ptr);
head->save_bytes = Z_TO_WORD_I(ptr);
head->flags_2 = Z_TO_WORD_I(ptr);
for (i = 0; i < 6; ++i)
head->serial_no[i] = Z_TO_BYTE_I(ptr);
head->common_word_o = Z_TO_WORD_I(ptr);
head->verify_length = Z_TO_WORD_I(ptr);
head->verify_checksum = Z_TO_WORD_I(ptr);
for (i = 0; i < 8; ++i)
head->padding1[i] = Z_TO_WORD_I(ptr);
head->fkey_o = Z_TO_WORD_I(ptr);
for (i = 0; i < 2; ++i)
head->padding2[i] = Z_TO_WORD_I(ptr);
head->alphabet_o = Z_TO_WORD_I(ptr);
for (i = 0; i < 5; ++i)
head->padding3[i] = Z_TO_WORD_I(ptr);
}
/*
* Function: read_header()
*
* Description:
* This function reads in the game data file's header info. We
* only do this between scr_setup() and scr_begin(), so just use
* normal printf()'s if we find an error, and just exit if we
* can't continue.
*
* Notes:
* This routine does not read the data-file header directly into
* a header structure because certain machines like the VAX
* 11/780 store integers in a different way to machines based on
* processors like the 68000 (a 68000 stores the high byte first,
* while a VAX stores the low byte first). Consequently, if the
* header is read directly into a structure, the integer values
* are interpreted differently by the two machines.
*/
void
read_header A1(header_t*, head)
{
extern void exit P((int));
header_t buffer;
if (fseek(game_file, 0L, 0) < 0)
{
f_error(errno, "Failed to seek to beginning of file `%s'", gname);
exit(1);
}
if (fread(&buffer, sizeof(header_t), 1, game_file) != 1)
{
f_error(errno, "Failed to read header of `%s'", gname);
exit(1);
}
assign(head, &buffer);
if (head->flags_1 & 0x01)
{
f_error(0, "Invalid header in file `%s'", gname);
exit(1);
}
}
/*
* Open a file for reading; if the parameter is NULL then look through
* the name,extension list pairs to try to find one there. Return a
* pointer to it, whatever it is.
*/
const char *
open_file A1(const char*, filename)
{
const char *fn = gname;
char *endp = gname;
if (filename != NULL)
{
const char **exp;
strcpy(gname, filename);
endp = &gname[strlen(gname)];
if ((game_file = fopen(gname, "rb")) != NULL)
{
int len;
for (exp=fext_lst; *exp != NULL; ++exp)
{
if (((len = strlen(*exp)) != 0) && !strcmp(endp - len, *exp))
break;
}
if (*exp != NULL)
endp -= len;
goto done;
}
for (exp = fext_lst; *exp != NULL; ++exp)
{
strcpy(endp, *exp);
if ((game_file = fopen(gname, "rb")) != NULL)
goto done;
}
f_error(errno, "Cannot open file `%s'", filename);
fn = NULL;
}
else
{
const char **nmp;
for (nmp = fname_lst; *nmp != NULL; ++nmp)
{
const char **exp;
strcpy(gname, *nmp);
endp = &gname[strlen(gname)];
for (exp = fext_lst; *exp != NULL; ++exp)
{
strcpy(endp, *exp);
if ((game_file = fopen(gname, "rb")) != NULL)
goto done;
}
}
f_error(0, "Could not find a game to play!", NULL);
fn = NULL;
}
done:
*endp = '\0';
strcpy(sname, gname);
#ifdef SAVE_EXT
strcat(sname, SAVE_EXT);
#endif
#ifdef SCRIPT_EXT
sprintf(script_fn, "%s%s", gname, SCRIPT_EXT);
#endif
return (fn);
}
void
close_file()
{
if (fclose(game_file))
scr_putline("Cannot Close Game File");
}
void
load_page A3(word, block, word, num_blocks, byte*, ptr)
{
extern file_t file_info;
long found;
long offset;
long num_bytes;
/*
* Read "num_block" blocks from Game File, starting with block
* "block", into the location pointed to by "ptr".
*/
offset = (long)block * BLOCK_SIZE;
num_bytes = (long)num_blocks * BLOCK_SIZE;
if (fseek(game_file, offset, 0) < 0)
{
f_error(errno, "Failed to seek to required offset in `%s'", gname);
quit();
}
else if ((found = fread(ptr, 1, num_bytes, game_file)) < num_bytes)
{
/*
* Check if this is the last block: some games (notably
* MS-DOS) don't have the full last block on the disk. If
* this isn't the last block, print an error. Otherwise, zero
* out the rest of the page.
*/
if ((found / BLOCK_SIZE != num_blocks - 1)
|| (block + num_blocks - 1 != file_info.pages))
{
f_error(errno, "Failed to load required blocks in `%s'", gname);
quit();
}
for (ptr += found; found < num_bytes; ++found, ++ptr)
*ptr = '\0';
}
}
void
save()
{
extern byte *base_ptr;
extern word save_blocks;
extern byte *end_res_p;
extern word *stack;
extern word *stack_base;
extern word *stack_var_ptr;
extern word pc_page;
extern word pc_offset;
FILE *fp;
int ret = 0;
/*
* We save the the program counter, the stack offset, the
* stack_var offset, the stack itself, and finally the resident
* impure storage. This overwrites the lowest 8 bytes of the
* stack; hopefully those aren't being used...
*/
if ((fp = scr_open_sf(MAXPATHLEN+1, (char *)sname, SF_SAVE)) == NULL)
{
if (errno != 0)
f_error(errno, "Cannot open save file `%s'", sname);
}
else
{
word *sp;
sp = (word *)end_res_p;
*(sp++) = pc_page;
*(sp++) = pc_offset;
*(sp++) = stack_base - stack;
*sp = stack_base - stack_var_ptr;
if ((fwrite(end_res_p, sizeof(byte), STACK_SIZE, fp) != STACK_SIZE)
|| (fwrite(base_ptr, BLOCK_SIZE, save_blocks, fp) != save_blocks))
{
f_error(errno, "Cannot write save file `%s'", sname);
fclose(fp);
}
else
{
scr_close_sf(sname, fp, SF_SAVE);
ret = 1;
}
}
ret_value(ret);
}
/*
* Check to see if a restored game is the same as our current game:
* note that everything except the serial number, verify length, and
* verify checksum must be identical. If they are copy over the new
* verify length and checksum so $verify will still work...
*/
static Bool
check A1(header_t*, info)
{
#define CMP(_1,_2,_f) ((_1)->_f == (_2)->_f)
extern header_t data_head;
Bool good = 0;
if (CMP(info, &data_head, z_version)
&& CMP(info, &data_head, release)
&& CMP(info, &data_head, resident_bytes)
&& CMP(info, &data_head, game_o)
&& CMP(info, &data_head, vocab_o)
&& CMP(info, &data_head, object_o)
&& CMP(info, &data_head, variable_o)
&& CMP(info, &data_head, save_bytes)
&& CMP(info, &data_head, common_word_o)
&& CMP(info, &data_head, fkey_o)
&& CMP(info, &data_head, alphabet_o))
{
data_head.flags_1 = info->flags_1;
data_head.verify_length = info->verify_length;
data_head.verify_checksum = info->verify_checksum;
good = 1;
}
return (good);
}
void
restore()
{
extern byte *base_ptr;
extern word save_blocks;
extern byte *end_res_p;
extern word *stack;
extern word *stack_base;
extern word *stack_var_ptr;
extern word pc_page;
extern word pc_offset;
FILE *fp;
int ret = 0;
int len = MAXPATHLEN+1;
errno = 0;
/*
* If we're restoring a game specified on the command line, print
* a message about it...
*/
if (gflags.game_state != PLAY_GAME)
{
char buf[MAXPATHLEN+30];
sprintf(buf, "Restoring saved game `%s' ...", sname);
if (gflags.game_state == NOT_INIT)
puts(buf);
else
scr_putline(buf);
len = 0;
}
/*
* Ask the user for a saved game filename to restore and open it;
* if that fails then print an error.
*/
if ((fp = scr_open_sf(len, (char *)sname, SF_RESTORE)) == NULL)
{
if (errno != 0)
f_error(errno, "Opening saved file ", sname);
ret = -1 + (gflags.game_state == INIT_GAME);
}
/*
* From here on we're destroying the current game data, so if the
* restore fails here we have no choice but to restart the game
* from scratch. Keep the scripting bit set correctly tho...
*/
else
{
Bool ok;
Bool scripting;
scripting = F2_IS_SET(B_SCRIPTING);
ok = ((fread(end_res_p, sizeof(byte), STACK_SIZE, fp)==STACK_SIZE)
&& (fread(base_ptr, BLOCK_SIZE, save_blocks, fp)==save_blocks));
if (scripting)
F2_SETB(B_SCRIPTING);
else
F2_RESETB(B_SCRIPTING);
if (!ok)
f_error(errno, "Error reading saved game file `%s'", sname);
else
{
header_t test;
assign(&test, (header_t *)base_ptr);
if (!check(&test))
f_error(0, "Invalid saved game file `%s'", sname);
else
{
word *sp;
sp = (word *)end_res_p;
pc_page = *(sp++);
pc_offset = *(sp++);
stack = stack_base - *(sp++);
stack_var_ptr = stack_base - *sp;
fix_pc();
ret = 1;
}
}
if (ret == 1)
scr_close_sf(sname, fp, SF_RESTORE);
else
fclose(fp);
}
if (gflags.game_state != NOT_INIT)
{
if (!ret)
{
strcpy(sname, gflags.filenm);
#ifdef SAVE_EXT
strcat(sname, SAVE_EXT);
#endif
scr_putline("Restarting...");
restart();
}
else
ret_value(ret > 0);
}
}